package top.yueyazhui.mysql_audit_log.util;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.yueyazhui.mysql_audit_log.entity.AuditLog;
import top.yueyazhui.mysql_audit_log.entity.AuditLogObjs;
import top.yueyazhui.mysql_audit_log.mapper.AuditLogMapper;
import top.yueyazhui.mysql_audit_log.mapper.AuditLogObjsMapper;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

@Component
public class AuditLogUtil {

    @Autowired
    AuditLogMapper auditLogMapper;
    @Autowired
    AuditLogObjsMapper auditLogObjsMapper;

    @Value("${yueyazhui.server.host}")
    private String HOST;
    @Value("${yueyazhui.server.username}")
    private String USERNAME;
    @Value("${yueyazhui.server.password}")
    private String PASSWORD;

    @Value("${yueyazhui.server.db-audit-log-path}")
    private String FILEPATH;
    @Value("${yueyazhui.server.db-audit-log-backup-path}")
    private String BACKUP_FILEPATH;
    private String FILENAME = "mysql-audit.json";

    private List<AuditLog> AuditLogCacheList = new ArrayList<>();
    private List<AuditLogObjs> AuditLogObjsCacheList = new ArrayList<>();

    public void saveAuditLogToMysQL() {
        String cmd = "cat " + FILEPATH + FILENAME;
        try {
            Connection connection = new Connection(HOST);
            connection.connect();
            boolean authenticate = connection.authenticateWithPassword(USERNAME, PASSWORD);
            if (!authenticate) {
                throw new RuntimeException("服务器认证失败");
            }
            Session session = connection.openSession();
            session.execCommand(cmd);
            InputStream stdout = new StreamGobbler(session.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
            while (true) {
                String line = br.readLine();
                if (line == null) {
                    break;
                }
                cache(line);
            }
            stdout.close();
            Session session1 = connection.openSession();
            session1.execCommand("mv " + FILEPATH + "mysql-audit.json " + BACKUP_FILEPATH + "mysql-audit.json.`date +%F`");
            session1.close();
            session.close();
            connection.close();
            refresh();
            save();
        } catch (Exception e) {
            e.getStackTrace();
        }
    }

    @Transactional
    public void save() {
        auditLogMapper.batchInsert(AuditLogCacheList);
        if (!(AuditLogObjsCacheList.isEmpty())) {
            auditLogObjsMapper.batchInsert(AuditLogObjsCacheList);
        }
    }

    private void refresh() {
        auditLogMapper.refresh();
    }

    private void cache(String jsonStr) throws Exception {
        jsonStr = replaceKey(jsonStr);
        JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
        AuditLog auditLog = new AuditLog();
        String id = UUID.fastUUID().toString();
        auditLog.setId(id);
        auditLog.setMsgType((String) jsonObject.get("msgType"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(Long.parseLong(((String) jsonObject.get("date"))));
        auditLog.setDate(sdf.parse(format));
        auditLog.setThreadId((String) jsonObject.get("threadId"));
        auditLog.setQueryId((String) jsonObject.get("queryId"));
        auditLog.setUser((String) jsonObject.get("user"));
        auditLog.setPrivUser((String) jsonObject.get("privUser"));
        auditLog.setIp((String) jsonObject.get("ip"));
        auditLog.setHost((String) jsonObject.get("host"));
        auditLog.setOs((String) jsonObject.get("os"));
        auditLog.setClientName((String) jsonObject.get("clientName"));
        auditLog.setPid((String) jsonObject.get("pid"));
        auditLog.setClientVersion((String) jsonObject.get("clientVersion"));
        auditLog.setPlatform((String) jsonObject.get("platform"));
        auditLog.setStatus((String) jsonObject.get("status"));
        auditLog.setCmd((String) jsonObject.get("cmd"));
        auditLog.setQuery((String) jsonObject.get("query"));
        auditLog.setRuntimeVersion((String) jsonObject.get("runtimeVersion"));
        auditLog.setClientLicense((String) jsonObject.get("clientLicense"));
        auditLog.setRuntimeVendor((String) jsonObject.get("runtimeVendor"));
        auditLog.setRowsNumber((String) jsonObject.get("rows"));
        List<AuditLogObjs> list = new ArrayList<>();
        JSONArray objects = ((JSONArray) jsonObject.get("objects"));
        if (objects != null) {
            for (Object object : objects) {
                AuditLogObjs auditLogObjs = new AuditLogObjs();
                JSONObject jsonObject1 = JSONUtil.parseObj(object);
                auditLogObjs.setId(UUID.fastUUID().toString());
                auditLogObjs.setAuditLogId(id);
                auditLogObjs.setDb((String) jsonObject1.get("db"));
                auditLogObjs.setName((String) jsonObject1.get("name"));
                auditLogObjs.setObjType((String) jsonObject1.get("objType"));
                list.add(auditLogObjs);
                AuditLogObjsCacheList.add(auditLogObjs);
            }
        }
        auditLog.setAuditLogObjsList(list);
        AuditLogCacheList.add(auditLog);
    }

    private String replaceKey(String jsonStr) {
        String newJsonStr = jsonStr
                .replace("\"msg-type\":", "\"msgType\":")
                .replace("\"thread-id\":", "\"threadId\":")
                .replace("\"query-id\":", "\"queryId\":")
                .replace("\"priv_user\":", "\"privUser\":")
                .replace("\"_os\":", "\"os\":")
                .replace("\"_client_name\":", "\"clientName\":")
                .replace("\"_pid\":", "\"pid\":")
                .replace("\"_client_version\":", "\"clientVersion\":")
                .replace("\"_platform\":", "\"platform\":")
                .replace("\"_runtime_version\":", "\"runtimeVersion\":")
                .replace("\"_client_license\":", "\"clientLicense\":")
                .replace("\"_runtime_vendor\":", "\"runtimeVendor\":")
                .replace("\"obj_type\":", "\"objType\":");
        return newJsonStr;
    }
}
